package com.yunxi.poc.starbucks.controller;


import com.yunxi.poc.starbucks.common.BaseController;
import com.yunxi.poc.starbucks.common.BizConstant;
import com.yunxi.poc.starbucks.entity.TOrderNew;
import com.yunxi.poc.starbucks.service.IBuyService;
import com.yunxi.poc.starbucks.vo.BuyVO;
import com.yunxi.poc.starbucks.vo.StoreRateVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author shiyuan.xlc
 * @since 2021-08-12
 */
@Controller
@RequestMapping("/starbucks/buy")
public class BuyController extends BaseController {
    private final static Logger logger = LoggerFactory.getLogger(BuyController.class);

    @Resource
    IBuyService buyService;

    @Resource
    ThreadPoolTaskExecutor executorService;

    @ResponseBody
    @RequestMapping(value = {""}, method = RequestMethod.POST)
    public ResponseEntity buySomething(@RequestBody BuyVO buyer) {
        // 打分计算
        List<StoreRateVO> storeRates = buyService.storeRatings(buyer.getLongitude(), buyer.getLatitude(), buyer.getBuyTime(), "", new TOrderNew());

        if (CollectionUtils.isEmpty(storeRates)) {
            return ResponseEntity.status(HttpStatus.OK).body("no stores nearby");
        }

        Map<String, Object> res = new HashMap<>();
        res.put("buyer", buyer);
        res.put("stores", storeRates);

        return ResponseEntity.status(HttpStatus.OK).body(res);
    }

    @ResponseBody
    @RequestMapping(value = {"/batch"}, method = RequestMethod.POST)
    public ResponseEntity batchMockBuyByStores(@RequestBody BuyVO buyer) {
        long secs = Duration.between(buyer.getStart(), buyer.getEnd()).getSeconds();
        long per = secs / BizConstant.BATCH_THREADS_STORE;

        for (String storeId : buyer.getStoreIds()) {
            LocalDateTime start = buyer.getStart();
            for (int i = 0; i < BizConstant.BATCH_THREADS_STORE; i++) {
                LocalDateTime end = start.plusSeconds(per);
                executorService.execute(getThread(start, end, storeId));
                start = end.plusSeconds(1);
            }
        }

        logger.info("Task count: " + executorService.getThreadPoolExecutor().getTaskCount() + " Task start at: " + LocalDateTime.now());
        // executorService.shutdown();
        return ResponseEntity.status(HttpStatus.OK).body("1");
    }

    private Runnable getThread(LocalDateTime start, LocalDateTime end, String storeId) {
        return () -> {
            logger.info("Task running ->" + " storeId: " + storeId + " start: " + start + " end: " + end);
            buyService.batchMockBuyByStores(start, end, new String[]{storeId});
            logger.info("Task done ->" + " storeId: " + storeId + " start: " + start + " end: " + end);

            logger.info("Task count: " + executorService.getThreadPoolExecutor().getTaskCount()
                    + " Task active count: " + (executorService.getActiveCount() - 1)
                    + " Task completed count: " + (executorService.getThreadPoolExecutor().getCompletedTaskCount() + 1)
                    + " Task ending at: " + LocalDateTime.now());
        };

            /*if (executorService.isTerminated()) {
                logger.info("all done!!!!!!");
            }*/
    }

    @ResponseBody
    @RequestMapping(value = {"/orders"}, method = RequestMethod.POST)
    public ResponseEntity batchmockBuyByOrders(@RequestBody BuyVO buyer) {
        executorService.execute(() -> {
            logger.info("Task running ->" + " orderIds: ");
            buyService.batchMockBuyByOrders(buyer.getOrderIds());
            logger.info("Task done ->" + " orderIds: ");
        });

        logger.info("Task count: " + executorService.getThreadPoolExecutor().getTaskCount());
        logger.info("Task start at: " + LocalDateTime.now());
        return ResponseEntity.status(HttpStatus.OK).body("1");
    }

    @ResponseBody
    @RequestMapping(value = {"/input"}, method = RequestMethod.POST)
    public ResponseEntity batchmockBuyByInput() {
        executorService.execute(() -> {
            logger.info("Task running ->");
            buyService.batchMockBuyByInputOrders();
            logger.info("Task done ->");
        });

        logger.info("Task count: " + executorService.getThreadPoolExecutor().getTaskCount());
        logger.info("Task start at: " + LocalDateTime.now());
        return ResponseEntity.status(HttpStatus.OK).body("1");
    }

}
